// Copyright DustedPixels.com 2008. All rights reserved.

package com.dustedpixels.jasmin.unit.z80.v1;

/**
 * @author micapolos@gmail.com (Michal Pociecha-Los)
 */
public final class InstructionDecoder {
  public int IN;
  
  public int MOP;
  public static final int MOP_NOP = 0x00;
  
  public int DATA_MUX;
  public int ADDR_MUX;
  
  public int REG_RD_MODE;
  public int REG_RD;
  
  public boolean REG_WR_ENABLE;
  public int REG_WR_MODE;
  public int REG_WR;  
  
  public boolean ACC_WR_ENABLE;
  
  public int DATA;
  public int ADDR;
  public boolean MREQ;
  public boolean IORQ;
  public boolean RD;
  public boolean WR;
  public boolean WAIT;
  
  private boolean wait;
  private boolean waitReg;
  private int opcodeReg;
  private int cycle;
  
  private int sss;
  private int ddd;
  
  Regs regs;
  Z80 z80;
  
  public void clockHigh() {
    REG_RD_ENABLE = false;
    REG_WR_ENABLE = false;
    ACC_RD_ENABLE = false;
    ACC_WR_ENABLE = false;
    MCYCLE_ENABLE = false;
    
    DATA_REQ = false;
    
    switch (opcodeReg) {
      // NOP
      case 0x00:
        break;
        
      // LD r,r'
      case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x046: case 0x47:
      case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x04E: case 0x4F:
      case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x056: case 0x57:
      case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x05E: case 0x5F:
      case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x066: case 0x67:
      case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x06E: case 0x6F:
      case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75:             case 0x77:
      case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x07E: case 0x7F:
        sss = opcodeReg & 0x07;
        ddd = (opcodeReg >>> 3) & 0x07;
        
        switch (sss) {
          case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
            // Put source register onto data bus
            assert (z80.dataMux == Z80.DATA_MUX_NONE);
            z80.dataMux = Z80.DATA_MUX_REGS;
            
            regs.MODE_OUT = Regs.MODE_8BIT;
            regs.REG_OUT = sss;
            
            // Put data bus into destination register
            assert (z80.regsMux == Z80.REGS_MUX_NONE);
            z80.regsMux = Z80.REGS_MUX_DATA;
            
            regs.WR = true;
            regs.MODE_IN = Regs.MODE_8BIT;
            regs.REG_IN = ddd;
            
            break;
          case 0x06:
            switch (cycle) {
              case 0:
                DATA_REQ = true;
                DATA_WR = false;
                break;
              case 1:
                break;
            }
            break;
          case 0x07:
            ACC_RD_ENABLE = true;
            break;
        }
        
        switch (ddd) {
          case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
            REG_WR_ENABLE = true;
            REG_WR = ddd;
            break;
          case 0x06:
            switch (cycle) {
              case 0:
                DATA_REQ = true;
                DATA_WR = true;
                break;
              case 1:
                break;
            }
            break;
          case 0x07:
            ACC_WR_ENABLE = true;
            break;
        }
        break;
    }
  }
  
  public void clockLow() {
    if (WR) {
      opcodeReg = IN;
      cycle = 0;
      waitReg = false;
    } else if (wait) {
      waitReg = true;
    } else {
      cycle++;
    }
  }
}
